package cloud.seri.iot.manager.service.mapper

import cloud.seri.iot.common.model.RegisterDevice
import cloud.seri.iot.manager.domain.Device
import cloud.seri.iot.manager.domain.DeviceStatus
import cloud.seri.iot.manager.service.dto.DeviceDTO
import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse
import com.aliyuncs.iot.model.v20180120.QueryDeviceResponse
import net.dreamlu.mica.core.utils.DateUtil
import org.mapstruct.Mapper
import org.mapstruct.Mapping
import org.mapstruct.Mappings
import org.mapstruct.Named
import org.springframework.data.mongodb.datatables.DataTablesOutput
import org.springframework.util.unit.DataUnit
import java.time.Instant

/**
 * Mapper for the entity [Device] and its DTO [DeviceDTO].
 */
@Mapper(componentModel = "spring", uses = [ProductMapper::class])
abstract class DeviceMapper : EntityMapper<DeviceDTO, Device>
{
    @Mappings(
        Mapping(source = "product.productKey", target = "productKey"),
        Mapping(source = "product.productName", target = "productName")
    )
    abstract override fun toDto(entity: Device): DeviceDTO

    @Mappings(
        Mapping(source = "productKey", target = "product")
    )
    abstract override fun toEntity(dto: DeviceDTO): Device

    abstract fun toDataTablesOutput(output: DataTablesOutput<Device>): DataTablesOutput<DeviceDTO>

    abstract fun deviceToRegisterDTO(deviceDTO: DeviceDTO): RegisterDevice

    @Mappings(
        Mapping(target = "createdDate", source = "gmtCreate", qualifiedByName = ["getInstant"]),
        Mapping(target = "activeDate", source = "gmtActive", qualifiedByName = ["getInstant"]),
        Mapping(target = "onlineDate", source = "gmtOnline", qualifiedByName = ["getInstant"]),
        Mapping(target = "status", source = "status", qualifiedByName = ["getStatus"])
    )
    abstract fun deviceDetailDataToEntity(data: QueryDeviceDetailResponse.Data): Device

    @Mappings(
        Mapping(target = "createdDate", source = "utcCreate", qualifiedByName = ["utcToInstant"]),
        Mapping(target = "lastModifiedDate", source = "utcModified", qualifiedByName = ["utcToInstant"]),
        Mapping(target = "product.productKey", source = "productKey"),
        Mapping(target = "status", source = "deviceStatus", qualifiedByName = ["getStatus"])
    )
    abstract fun deviceInfoToEntity(deviceInfo: QueryDeviceResponse.DeviceInfo): Device

    abstract fun fromId(iotId: String?): Device?

    @Named("getInstant")
    fun getTimeStamp(date: String?): Instant?
    {
        if (date.isNullOrBlank())
            return null
        return Instant.ofEpochMilli(DateUtil.parse(date, "yyyy-MM-dd HH:mm:ss").time)
    }

    @Named("utcToInstant")
    fun utcToInstant(utc: String?): Instant?
    {
        if (utc.isNullOrBlank())
            return null
        return Instant.ofEpochMilli(DateUtil.parse(utc, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").time)
    }

    @Named("getStatus")
    fun getStatus(status: String): Int
    {
        return DeviceStatus.valueOf(status).ordinal
    }
}
